////---------------------------------------------------------------------------
////
//// (c) Copyright Microsoft Corporation.
//// This source is subject to the Microsoft Limited Permissive License.
//// See http://www.microsoft.com/resources/sharedsource/licensingbasics/limitedpermissivelicense.mspx
//// All other rights reserved.
////
//// This file is part of the 3D Tools for Windows Presentation Foundation
//// project.  For more information, see:
//// 
//// http://CodePlex.com/Wiki/View.aspx?ProjectName=3DTools
////
////---------------------------------------------------------------------------

//using System;
//using System.Collections;
//using System.Collections.Generic;
//using System.Windows;
//using System.Windows.Controls;
//using System.Windows.Data;
//using System.Windows.Documents;
//using System.Windows.Media;
//using System.Windows.Media.Imaging;
//using System.Windows.Media.Media3D;
//using System.Windows.Shapes;
//using System.Windows.Input;
//using System.Windows.Markup; // IAddChild, ContentPropertyAttribute

//namespace _3DTools
//{
//    /// <summary>
//    /// This class enables a Viewport3D to be enhanced by allowing UIElements to be placed 
//    /// behind and in front of the Viewport3D.  These can then be used for various enhancements.  
//    /// For examples see the Trackball, or InteractiveViewport3D.
//    /// </summary>
//    [ContentProperty("Content")]    
//    public abstract class Viewport3DDecorator : FrameworkElement, IAddChild
//    {
//        /// <summary>
//        /// Creates the Viewport3DDecorator
//        /// </summary>
//        public Viewport3DDecorator()
//        {
//            // create the two lists of children
//            _preViewportChildren = new UIElementCollection(this, this);
//            _postViewportChildren = new UIElementCollection(this, this);
                    
//            // no content yet
//            _content = null;
//        }           

//        /// <summary>
//        /// The content/child of the Viewport3DDecorator.  A Viewport3DDecorator only has one
//        /// child and this child must be either another Viewport3DDecorator or a Viewport3D.
//        /// </summary>
//        public UIElement Content
//        {
//            get
//            {
//                return _content;
//            }

//            set
//            {
//                // check to make sure it is a Viewport3D or a Viewport3DDecorator                
//                if (!(value is Viewport3D || value is Viewport3DDecorator))
//                {
//                    throw new ArgumentException("Not a valid child type", "value");
//                }            
                
//                // check to make sure we're attempting to set something new
//                if (_content != value)
//                {
//                    UIElement oldContent = _content;
//                    UIElement newContent = value;                    
                    
//                    // remove the previous child
//                    RemoveVisualChild(oldContent);
//                    RemoveLogicalChild(oldContent);
                    
//                    // set the private variable
//                    _content = value;

//                    // link in the new child
//                    AddLogicalChild(newContent);
//                    AddVisualChild(newContent);

//                    // let anyone know that derives from us that there was a change
//                    OnViewport3DDecoratorContentChange(oldContent, newContent);

//                    // data bind to what is below us so that we have the same width/height
//                    // as the Viewport3D being enhanced
//                    // create the bindings now for use later
//                    BindToContentsWidthHeight(newContent);
                                      
//                    // Invalidate measure to indicate a layout update may be necessary
//                    InvalidateMeasure();
//                }
//            }
//        }

//        /// <summary>
//        /// Data binds the (Max/Min)Width and (Max/Min)Height properties to the same
//        /// ones as the content.  This will make it so we end up being sized to be
//        /// exactly the same ActualWidth and ActualHeight as waht is below us.
//        /// </summary>
//        /// <param name="newContent">What to bind to</param>
//        private void BindToContentsWidthHeight(UIElement newContent)
//        {
//            // bind to width height
//            Binding _widthBinding = new Binding("Width");
//            _widthBinding.Mode = BindingMode.OneWay;
//            Binding _heightBinding = new Binding("Height");
//            _heightBinding.Mode = BindingMode.OneWay;

//            _widthBinding.Source = newContent;
//            _heightBinding.Source = newContent;

//            BindingOperations.SetBinding(this, WidthProperty, _widthBinding);
//            BindingOperations.SetBinding(this, HeightProperty, _heightBinding);

            
//            // bind to max width and max height
//            Binding _maxWidthBinding = new Binding("MaxWidth");
//            _maxWidthBinding.Mode = BindingMode.OneWay;
//            Binding _maxHeightBinding = new Binding("MaxHeight");
//            _maxHeightBinding.Mode = BindingMode.OneWay;

//            _maxWidthBinding.Source = newContent;
//            _maxHeightBinding.Source = newContent;

//            BindingOperations.SetBinding(this, MaxWidthProperty, _maxWidthBinding);
//            BindingOperations.SetBinding(this, MaxHeightProperty, _maxHeightBinding);

            
//            // bind to min width and min height
//            Binding _minWidthBinding = new Binding("MinWidth");
//            _minWidthBinding.Mode = BindingMode.OneWay;
//            Binding _minHeightBinding = new Binding("MinHeight");
//            _minHeightBinding.Mode = BindingMode.OneWay;

//            _minWidthBinding.Source = newContent;
//            _minHeightBinding.Source = newContent;

//            BindingOperations.SetBinding(this, MinWidthProperty, _minWidthBinding);
//            BindingOperations.SetBinding(this, MinHeightProperty, _minHeightBinding);            
//        }

//        /// <summary>
//        /// Extenders of Viewport3DDecorator can override this function to be notified
//        /// when the Content property changes
//        /// </summary>
//        /// <param name="oldContent">The old value of the Content property</param>
//        /// <param name="newContent">The new value of the Content property</param>
//        protected virtual void OnViewport3DDecoratorContentChange(UIElement oldContent, UIElement newContent)
//        {
//        }

//        /// <summary>
//        /// Property to get the Viewport3D that is being enhanced.
//        /// </summary>
//        public Viewport3D Viewport3D
//        {
//            get
//            {
//                Viewport3D viewport3D = null;
//                Viewport3DDecorator currEnhancer = this;

//                // we follow the enhancers down until we get the
//                // Viewport3D they are enhancing
//                while (true)
//                {
//                    UIElement currContent = currEnhancer.Content;

//                    if (currContent == null)
//                    {
//                        break;
//                    }
//                    else if (currContent is Viewport3D)
//                    {
//                        viewport3D = (Viewport3D)currContent;
//                        break;
//                    }
//                    else
//                    {
//                        currEnhancer = (Viewport3DDecorator)currContent;
//                    }                    
//                }

//                return viewport3D;
//            }
//        }        

//        /// <summary>
//        /// The UIElements that occur before the Viewport3D
//        /// </summary>
//        protected UIElementCollection PreViewportChildren
//        {
//            get
//            {
//                return _preViewportChildren;
//            }
//        }

//        /// <summary>
//        /// The UIElements that occur after the Viewport3D
//        /// </summary>
//        protected UIElementCollection PostViewportChildren
//        {
//            get
//            {
//                return _postViewportChildren;
//            }
//        }
       
//        /// <summary>
//        /// Returns the number of Visual children this element has.
//        /// </summary>
//        protected override int VisualChildrenCount
//        {
//            get 
//            {
//                int contentCount = (Content == null ? 0 : 1);

//                return PreViewportChildren.Count +
//                       PostViewportChildren.Count + 
//                       contentCount; 
//            }
//        }

//        /// <summary>
//        /// Returns the child at the specified index.
//        /// </summary>
//        protected override Visual GetVisualChild(int index)
//        {
//            int orginalIndex = index;

//            // see if index is in the pre viewport children
//            if (index < PreViewportChildren.Count)
//            {
//                return PreViewportChildren[index];
//            }
//            index -= PreViewportChildren.Count;

//            // see if it's the content
//            if (Content != null && index == 0)
//            {
//                return Content;
//            }
//            index -= (Content == null ? 0 : 1);

//            // see if it's the post viewport children
//            if (index < PostViewportChildren.Count)
//            {
//                return PostViewportChildren[index];
//            }

//            // if we didn't return then the index is out of range - throw an error
//            throw new ArgumentOutOfRangeException("index", orginalIndex, "Out of range visual requested");
//        }

//        /// <summary> 
//        /// Returns an enumertor to this element's logical children
//        /// </summary>
//        protected override IEnumerator LogicalChildren
//        {
//            get
//            {
//                Visual[] logicalChildren = new Visual[VisualChildrenCount];

//                for (int i = 0; i < VisualChildrenCount; i++)
//                {
//                    logicalChildren[i] = GetVisualChild(i);
//                }

//                // return an enumerator to the ArrayList
//                return logicalChildren.GetEnumerator();
//            }
//        }

//        /// <summary>
//        /// Updates the DesiredSize of the Viewport3DDecorator
//        /// </summary>
//        /// <param name="constraint">The "upper limit" that the return value should not exceed</param>
//        /// <returns>The desired size of the Viewport3DDecorator</returns>
//        protected override Size MeasureOverride(Size constraint)
//        {
//            Size finalSize = new Size();    

//            MeasurePreViewportChildren(constraint);

//            // measure our Viewport3D(Enhancer)
//            if (Content != null)
//            {
//                Content.Measure(constraint);
//                finalSize = Content.DesiredSize;
//            }

//            MeasurePostViewportChildren(constraint);

//            return finalSize;
//        }

//        /// <summary>
//        /// Measures the size of all the PreViewportChildren.  If special measuring behavior is needed, this
//        /// method should be overridden.
//        /// </summary>
//        /// <param name="constraint">The "upper limit" on the size of an element</param>
//        protected virtual void MeasurePreViewportChildren(Size constraint)
//        {
//            // measure the pre viewport children
//            MeasureUIElementCollection(PreViewportChildren, constraint);
//        }

//        /// <summary>
//        /// Measures the size of all the PostViewportChildren.  If special measuring behavior is needed, this
//        /// method should be overridden.
//        /// </summary>
//        /// <param name="constraint">The "upper limit" on the size of an element</param>
//        protected virtual void MeasurePostViewportChildren(Size constraint)
//        {
//            // measure the post viewport children
//            MeasureUIElementCollection(PostViewportChildren, constraint);
//        }

//        /// <summary>
//        /// Measures all of the UIElements in a UIElementCollection
//        /// </summary>
//        /// <param name="collection">The collection to measure</param>
//        /// <param name="constraint">The "upper limit" on the size of an element</param>
//        private void MeasureUIElementCollection(UIElementCollection collection, Size constraint)
//        {
//            // measure the pre viewport visual visuals
//            foreach (UIElement uiElem in collection)
//            {
//                uiElem.Measure(constraint);
//            }
//        }
        
//        /// <summary>
//        /// Arranges the Pre and Post Viewport children, and arranges itself
//        /// </summary>
//        /// <param name="arrangeSize">The final size to use to arrange itself and its children</param>
//        protected override Size ArrangeOverride(Size arrangeSize)
//        {
//            ArrangePreViewportChildren(arrangeSize);

//            // arrange our Viewport3D(Enhancer)
//            if (Content != null)
//            {
//                Content.Arrange(new Rect(arrangeSize));
//            }

//            ArrangePostViewportChildren(arrangeSize);

//            return arrangeSize;
//        }

//        /// <summary>
//        /// Arranges all the PreViewportChildren.  If special measuring behavior is needed, this
//        /// method should be overridden.
//        /// </summary>
//        /// <param name="arrangeSize">The final size to use to arrange each child</param>
//        protected virtual void ArrangePreViewportChildren(Size arrangeSize)
//        {
//            ArrangeUIElementCollection(PreViewportChildren, arrangeSize);
//        }

//        /// <summary>
//        /// Arranges all the PostViewportChildren.  If special measuring behavior is needed, this
//        /// method should be overridden.
//        /// </summary>
//        /// <param name="arrangeSize">The final size to use to arrange each child</param>
//        protected virtual void ArrangePostViewportChildren(Size arrangeSize)
//        {
//            ArrangeUIElementCollection(PostViewportChildren, arrangeSize);
//        }

//        /// <summary>
//        /// Arranges all the UIElements in the passed in UIElementCollection
//        /// </summary>
//        /// <param name="collection">The collection that should be arranged</param>
//        /// <param name="constraint">The final size that element should use to arrange itself and its children</param>
//        private void ArrangeUIElementCollection(UIElementCollection collection, Size constraint)
//        {
//            // measure the pre viewport visual visuals
//            foreach (UIElement uiElem in collection)
//            {
//                uiElem.Arrange(new Rect(constraint));
//            }
//        }

//        //------------------------------------------------------
//        //
//        //  IAddChild implementation
//        //
//        //------------------------------------------------------

//        void IAddChild.AddChild(Object value)
//        {
//            // check against null
//            if (value == null)
//            {
//                throw new ArgumentNullException("value");
//            }

//            // we only can have one child
//            if (this.Content != null)
//            {
//                throw new ArgumentException("Viewport3DDecorator can only have one child");
//            }

//            // now we can actually set the content
//            Content = (UIElement)value;
//        }

//        void IAddChild.AddText(string text)
//        {
//            // The only text we accept is whitespace, which we ignore.
//            for (int i = 0; i < text.Length; i++)
//            {
//                if (!Char.IsWhiteSpace(text[i]))
//                {
//                    throw new ArgumentException("Non whitespace in add text", text);
//                }
//            }
//        }

//        //---------------------------------------------------------
//        // 
//        //  Private data
//        //
//        //---------------------------------------------------------        
//        private UIElementCollection _preViewportChildren;
//        private UIElementCollection _postViewportChildren;
//        private UIElement _content;
//    }
//}

